﻿using System;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace AOUtils.Libraries
{
    [XmlRoot("items")]
    public class OptimizedXml
    {
        public delegate bool Predicate<T>(T inputValue);
        public delegate bool Predicate<T,I>(T inputValue,I param);
        public delegate bool Predicate<T, I, J>(T inputValue, I param, J param2);
        public static event EventHandler<ProgressUpdateEventArgs> ProgressUpdate;

        public OptimizedXml()
        {
            Items = new List<OptimizedItem>();
        }
        public static explicit operator OptimizedXml(AOMainframeXml xml)
        {
            OptimizedXml oxml = new OptimizedXml();
            int counter, current, previous;
            counter = current = previous = 0;
            foreach (Item item in xml.Items)
            {
                counter++;
                oxml.Items.Add((OptimizedItem)item);
                current = 100 * counter / xml.Items.Count;
                if (current != previous && ProgressUpdate != null)
                {
                    ProgressUpdate(oxml, new ProgressUpdateEventArgs(current));
                    previous = current;
                }
            }
            return oxml;
        }

        [XmlElement("item", typeof(OptimizedItem))]
        public List<OptimizedItem> Items
        {
            get;
            set;
        }

        public IEnumerable<T> Filter<T>(IEnumerable<T> list, Predicate<T> condition)
        {
            return Filter<T>(list, condition, false);
        }

        public IEnumerable<T> Filter<T>(IEnumerable<T> list, Predicate<T> condition, bool reportProgress)
        {
            int counter, current, previous;
            counter = current = previous = 0;

            foreach (T item in list)
            {
                counter++;
                current = 100 * counter / Items.Count;
                if (reportProgress && current != previous && ProgressUpdate != null)
                {
                    ProgressUpdate(this, new ProgressUpdateEventArgs(current));
                    previous = current;
                }
                if (condition(item))
                    yield return item;
            }
        }

        public IEnumerable<T> Filter<T, I>(IEnumerable<T> list, Predicate<T, I> condition, I param)
        {
            return Filter<T, I>(list, condition, param, false);
        }

        public IEnumerable<T> Filter<T,I>(IEnumerable<T> list, Predicate<T,I> condition,I param, bool reportProgress)
        {
            int counter, current, previous;
            counter = current = previous = 0;

            foreach (T item in list)
            {
                counter++;
                current = 100 * counter / Items.Count;
                if (reportProgress && current != previous && ProgressUpdate != null)
                {
                    ProgressUpdate(this, new ProgressUpdateEventArgs(current));
                    previous = current;
                }
                if (condition(item, param))
                    yield return item;
            }
        }

        public IEnumerable<T> Filter<T, I, J>(IEnumerable<T> list, Predicate<T, I, J> condition, I param, J param2, bool reportProgress)
        {
            int counter, current, previous;
            counter = current = previous = 0;

            foreach (T item in list)
            {
                counter++;
                current = 100 * counter / Items.Count;
                if (reportProgress && current != previous && ProgressUpdate != null)
                {
                    ProgressUpdate(this, new ProgressUpdateEventArgs(current));
                    previous = current;
                }
                if (condition(item, param, param2))
                    yield return item;
            }
        }

        public IEnumerable<OptimizedItem> SpiritImplants(IEnumerable<OptimizedItem> list)
        {
            return Filter<OptimizedItem>(list, delegate(OptimizedItem item)
            {
                return (item.EquipmentPage & (EquipmentPage.Implant | EquipmentPage.Spirit)) > 0;
            });
        }

        public IEnumerable<OptimizedItem> Armors(IEnumerable<OptimizedItem> list)
        {
            return Filter<OptimizedItem>(list, delegate(OptimizedItem item)
            {
                return (item.EquipmentPage & EquipmentPage.Armor) > 0;
            });
        }

        public IEnumerable<OptimizedItem> Weapons(IEnumerable<OptimizedItem> list)
        {
            return Filter<OptimizedItem>(list, delegate(OptimizedItem item)
            {
                return (item.EquipmentPage & EquipmentPage.Weapon) > 0;
            });
        }

        public IEnumerable<OptimizedItem> HasFlag(IEnumerable<OptimizedItem> list, Flags flag)
        {
            return Filter<OptimizedItem, Flags>(list, delegate(OptimizedItem item, Flags searchFlag)
            {
                return ((item.Flags & searchFlag) > 0);
            }, flag);
        }

        public IEnumerable<OptimizedItem> HasNotFlag(IEnumerable<OptimizedItem> list, Flags flag)
        {
            return Filter<OptimizedItem, Flags>(list, delegate(OptimizedItem item, Flags searchFlag)
            {
                return ((item.Flags & searchFlag) == 0);
            }, flag);
        }

        public IEnumerable<OptimizedItem> HasSkill(IEnumerable<OptimizedItem> list, string skill)
        {
            return HasSkill(list, skill, false);
        }

        public IEnumerable<OptimizedItem> HasSkill(IEnumerable<OptimizedItem> list, string skill, bool reportProgress)
        {
            return Filter<OptimizedItem, string>(list, delegate(OptimizedItem item, string searchskill)
            {
                if (item.OnWear.Functions.Contains(FunctionType.Modify))
                {
                    if (item.OnWear.Functions[FunctionType.Modify].Targets.Contains(TargetType.Wearer))
                    {
                        foreach (OptimizedArgument arg in item.OnWear.Functions[FunctionType.Modify].Targets[TargetType.Wearer].Arguments)
                        {
                            if (arg.Value.Equals(searchskill))// && item.GetSkillValues()[searchskill] > 0)
                                return true;
                        }
                    }
                    if (item.OnWear.Functions[FunctionType.Modify].Targets.Contains(TargetType.Target))
                    {
                        foreach (OptimizedArgument arg in item.OnWear.Functions[FunctionType.Modify].Targets[TargetType.Target].Arguments)
                        {
                            if (arg.Value.Equals(searchskill))// && item.GetSkillValues()[searchskill] > 0)
                                return true;
                        }
                    }
                }
                return false;
            }, skill, reportProgress);
        }

        public IEnumerable<OptimizedItem> HasSkill(IEnumerable<OptimizedItem> list, string skill, Professions profession, bool reportProgress)
        {
            return Filter<OptimizedItem, string, Professions>(list, delegate(OptimizedItem item, string searchskill, Professions searchprofession)
            {
                if (item.OnWear.Functions.Contains(FunctionType.Modify))
                {
                    if (item.OnWear.Functions[FunctionType.Modify].Targets.Contains(TargetType.Wearer))
                    {   
                        foreach (OptimizedArgument arg in item.OnWear.Functions[FunctionType.Modify].Targets[TargetType.Wearer].Arguments)
                        {
                            if (arg.Value.Equals(searchskill))
                                if (arg.Requirements.Count > 0)
                                {
                                    foreach (OptimizedRequirement req in arg.Requirements)
                                    {
                                        if ((req.Statistic == "Profession" || req.Statistic == "VisualProfession") && req.Operator == OperatorType.EqualTo && ((Professions)Enum.Parse(typeof(Professions), req.Value.Replace(" ", "").Replace("-", "")) & searchprofession) == 0)
                                            return false;
                                    }
                                    return true;
                                }
                                else
                                    return true;
                        }
                    }
                    if (item.OnWear.Functions[FunctionType.Modify].Targets.Contains(TargetType.Target))
                    {
                        foreach (OptimizedArgument arg in item.OnWear.Functions[FunctionType.Modify].Targets[TargetType.Target].Arguments)
                        {
                            if (arg.Value.Equals(searchskill))
                                if (arg.Requirements.Count > 0)
                                {
                                    foreach (OptimizedRequirement req in arg.Requirements)
                                    {
                                        if ((req.Statistic == "Profession" || req.Statistic == "VisualProfession") && req.Operator == OperatorType.EqualTo && ((Professions)Enum.Parse(typeof(Professions), req.Value.Replace(" ", "").Replace("-", "")) & searchprofession) > 0)
                                            return true;
                                    }
                                }
                                else
                                    return true;
                        }
                    }
                }
                return false;
            }, skill, profession, reportProgress);
        }
    }
}
